Fill-rate, Canvases and input

译文

Fill-rate, Canvases and input
填充率,画布和输入

版本检查: 2017.3
难度: 高级

This chapter discusses broader issues with structuring Unity UIs.
本章讨论构建Unity UI的更广泛问题。

Remediating fill-rate issues
修复填充率问题

There are two courses of action that can be taken to reduce the stress on the GPU’s fragment pipeline:
可以采取两种措施来减轻GPU片段管道的压力:

      ●  Reducing the complexity of fragment shaders. See the “UI shaders and low-spec devices” section for more details.
          降低片段着色器的复杂性。有关详细信息,请参阅“UI shaders and low-spec devices”部分。

      ●  Reducing the number of pixels that must be sampled.
          减少采样的像素数量

As the UI shader is generally standardized, the most common problem is simply excessive fill-rate usage. This is most commonly due to a large number of overlapping UI elements and/or having multiple UI elements that occupy significant portions of the screen. Both of these problems can lead to extremely high levels of overdraw.
由于UI着色器通常是标准化的,因此最常见的问题是过度使用填充率过高。这通常是由于大量重叠的UI元素和/或具有占据屏幕的重要部分的多个UI元素。这两个问题都可能导致极高的透支度。

In order to alleviate fill-rate overutilization and reduce overdraw, consider the following possible remediations.
为了减少填充率过度使用并减少过度抽取,请考虑以下可能的补救措施。

Eliminating invisible UI
消除不可见的UI

TThe method that requires the least redesigning of existing UI elements is to simply disable elements that are not visible to the player. The most common case where this is applicable is opening full-screen UIs with opaque backgrounds. In this case, any UI elements placed beneath the full-screen UI can be disabled.
减少重新设计现有UI元素的方法是简单的禁用看不见的UI元素。最常见的情况是打开具有不透明背景的全屏UI。在这种情况下,可以禁用放置在全屏UI下方的任何UI元素。

The simplest way to do this is to disable the root GameObject or GameObjects containing the invisible UI elements. For an alternate solution, see the Disabling Canvases section.
最简单的方法是禁用根结点GameObject或者包含看不见UI元素的GameObject。更多的解决方案,请参阅Disabling Canvases部分。

Finally, make sure that no UI elements are hidden by setting their alpha to 0, as the element will still be sent to the GPU and may take precious rendering time. If a UI element doesn’t need a Graphic component, you can simply remove it and raycasting will still work.
最后,通过将其alpha设置为0来确保没有隐藏UI元素,因为该元素仍将被发送到GPU并且可能需要很多的渲染时间。如果UI元素不需要Graphic组件,您只需删除它,光线投射仍然可以工作。

Simplify UI structure
简化UI结构

To reduce the time required to rebuild and render the UI, it is important to keep the number of UI objects as low as possible. Try to bake things as much as you can. For example, don’t use a blended GameObject just to change the hue to an element, do this via material properties instead. Also, don’t create game objects acting like folders and having no other purpose than organizing your Scenes.
为了减少重建和呈现UI所需的时间,保持UI对象的数量尽可能低是很重要的。尽量把东西烤得尽可能多。例如,不要仅仅使用混合的GameObject来将色调更改为元素,而是通过材质属性来实现。另外,不要创建像文件夹一样的游戏对象,除了组织你的场景之外,没有其他目的。

Disabling invisible camera output
禁用隐藏相机的输出

If a full-screen UI with an opaque background is opened, the world-space camera will still render the standard 3D scene behind the UI. The renderer is not aware that the full-screen Unity UI will obscure the entire 3D scene.
如果打开具有不透明背景的全屏UI,则世界空间相机仍将在UI后面呈现标准3D场景。渲染器不知道全屏Unity UI会遮挡整个3D场景。

Therefore, if a completely full-screen UI is opened, disabling any and all of the obscured world-space cameras will help reduce GPU stress by simply eliminating the useless work of rendering the 3D world.
因此,如果一个完全全屏的用户界面被打开,禁用任何和所有被模糊的世界空间相机将有助于减少GPU的压力,因为它可以简单地消除渲染3D世界的无用工作。

If the UI doesn’t cover the whole 3D scene, you may want to render the scene to a texture once and use it instead of continuously render it. You will lose the possibility to see animated content in the 3D scene, but that should be acceptable most of the time.
如果UI不覆盖整个3D场景,你可能想要将场景渲染到纹理上,然后使用它,而不是持续渲染它。你将失去在3D场景中看到动画内容的可能性,但这在大多数情况下都是可以接受的。

Note: If a Canvas is set as “Screen Space – Overlay”, then it will be drawn irrespective of the number of cameras active in the scene.
注意:如果一个画布被设置为“Screen Space – Overlay”,那么无论在场景中活动的摄像机数量有多少,它都会被绘制出来。

Majority-obscured cameras
多数-遮挡相机

Many “full-screen” UIs do not actually obscure the entire 3D world, but leave a small portion of the world visible. In these cases, it may be more optimal to capture just the portions of the world that are visible into a render texture. If the visible portion of the world is “cached” in a render texture, then the actual world-space camera can be disabled, and the cached render texture can be drawn behind the UI screen to provide an impostor version of the 3D world.
许多“全屏”用户界面实际上并不掩盖整个3D世界,但却让世界的一小部分可见。在这些情况下,捕获渲染纹理中可见的世界部分可能更为理想。如果世界的可见部分在渲染纹理中“缓存”,则可以禁用实际的世界空间相机,并且可以在UI屏幕后面绘制缓存的渲染纹理以提供3D世界的顶替版本。

Composition-based UIs
基于组合的UI

It is very common for designers to create UIs via composition – combining and layering standard backgrounds and elements to create the final UI. While this is relatively simple to do, and very friendly to iteration, it is non-performant due to Unity UI’s use of the transparent rendering queue.
对于设计师来说,通过组合创建UI是很常见的——组合和分层标准背景和元素,以创建最终的UI。虽然这相对来说比较简单,而且对迭代非常友好,但由于Unity UI使用透明呈现队列,因此它不具备高性能。

Consider a simple UI with a background, a button and some text on the button. Because objects in the transparent queue are sorted from back to front, in the case that a pixel falls within a text glyph, the GPU must sample the background’s texture, then the button’s texture, and finally the text atlas’ texture, for a total of three samples. As the complexity of the UI grows, and more decorative elements are layered onto the background, the number of samples can rise rapidly.
考虑一个简单的UI,有背景、按钮和按钮上的一些文本。因为透明队列中的对象是从后到前排序的,如果一个像素落在一个文本字形内,那么GPU必须对背景的纹理进行采样,然后是按钮的纹理,最后是文本图集的纹理,总共有三个样本。随着UI的复杂性增加,更多的装饰性元素被分层放置在背景中,样本的数量会迅速增加。

If a large UI is discovered to be fill-rate bound, the best recourse is to create specialized UI sprites that merge as many of the decorative/invariant elements of the UI into its background texture. This reduces the number of elements that must be layered atop one another to achieve the desired design, but is labor-intensive and increases the size of the project’s texture atlases.
如果一个大型UI被发现是填充率绑定的,最好的办法是创建专门的UI精灵,将UI的装饰/不变元素合并到它的背景纹理中。这减少了必须分层的元素的数量,以达到所需的设计,但是是劳动密集型的,并且增加了项目纹理地图集的大小。

This principle of condensing the number of layered elements necessary to create a given UI onto specialized UI sprites can also be used for sub-elements. Consider a store UI with a scrolling pane of products. Each product UI element has a border, a background, and some icons to denote price, name and other information.
将创建给定UI所需的分层元素数量压缩到专门的UI精灵的这一原则也可以用于子元素。考虑一个带有滚动列表的商店UI。每个产品UI元素都有一个边框、一个背景和一些图标来表示价格、名称和其他信息。

The store UI will need a background, but because its products scroll across the background, the product elements cannot be merged onto the store UI’s background texture. However, the border, price, name and other elements of the product’s UI element could be merged onto the product’s background. Depending on the size and number of icons, the fill-rate savings can be considerable.
商店UI需要一个背景,但是因为它的产品在背景中滚动,所以产品元素不能被合并到商店UI的背景纹理中。然而,产品的UI元素的边框、价格、名称和其他元素可以合并到产品的背景中。根据图标的大小和数量,可以节省大量的填充率。

There are several drawbacks to combining layered elements. Specialized elements can no longer be reused, and require additional artist resources to create. The addition of large new textures may significantly increase the amount of memory needed to hold the UI textures, particularly if the UI textures are not loaded and unloaded on demand.
将分层的元素组合在一起有几个缺点。专门化元素不能再被重用,并且需要额外的美术资源来创建。添加大的新纹理可能会显著的增加保存UI纹理所需的内存量,特别是如果UI纹理没有按需加载和卸载的情况下。

UI shaders and low-spec devices
UI着色器和低配置的设备

The built-in shader used by Unity UI incorporates support for masking, clipping and numerous other complex operations. Because of this added complexity, the UI shader performs poorly compared to the simpler Unity 2D shader on low-end devices such as the iPhone 4.
Unity UI使用的内置着色器包含对屏蔽,剪切和许多其他复杂操作的支持。由于这种增加的复杂性,与较低端设备(如iPhone 4)上的简单Unity 2D着色器相比,UI着色器的性能很低。

If masking, clipping and other “fancy” features are unneeded for an application targeted at low-end devices, it is possible to create a custom shader that omits the unused operations, such as this minimal UI shader:
如果针对低端设备的应用程序不需要屏蔽、剪切和其他“花哨”功能,那么就可以创建一个定制着色器来省略未使用的操作,比如这个最小的UI着色器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
Shader "UI/Fast-Default"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)
}

SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}

Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"
#include "UnityUI.cginc"

struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};

struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
half2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
};

fixed4 _Color;
fixed4 _TextureSampleAdd;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.worldPosition = IN.vertex;
OUT.vertex = mul(UNITY_MATRIX_MVP, OUT.worldPosition);

OUT.texcoord = IN.texcoord;

#ifdef UNITY_HALF_TEXEL_OFFSET
OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1);
#endif

OUT.color = IN.color * _Color;
return OUT;
}

sampler2D _MainTex;
fixed4 frag(v2f IN) : SV_Target
{
return (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
}
ENDCG
}
}
}

UI Canvas rebuilds
UI画布重建

To display any UI, the UI system must construct geometry for each UI component represented on-screen. This includes running dynamic layout code, generating polygons to represent characters in UI text strings, and merging as much geometry as possible into single meshes in order to minimize draw calls. This is a multi-step process and is described in detail in the Fundamentals section at the beginning of this guide.
为了显示任何UI,UI系统必须为屏幕上显示的每个UI组件构造几何图形。这包括运行动态布局代码,生成多边形来表示UI文本字符串中的字符,并将尽可能多的几何图形合并到单个网格中,以最小化绘制调用。这是一个多步骤的过程,在本指南开始的基础部分中详细描述。

Canvas rebuilds can become performance problems for two primary reasons:
画布重建会影响性能问题,主要有两个原因:

      ●  If the number of drawable UI elements on a Canvas is large, then calculating the batch itself becomes very expensive. This is because the cost of sorting and analyzing the elements grows more-than-linearly to the number of drawable UI elements on the Canvas.
          如果画布上可绘制的UI元素的数量很大,那么计算批处理本身就变得非常昂贵。这是因为对元素进行排序和分析的成本增长的速度超过了画布上可绘制的UI元素的数量。

      ●  If the Canvas is dirtied frequently, then excessive time may be spent refreshing a Canvas that has relatively few changes.
          如果画布经常被标记为dirty,那么可能会花费过多的时间来刷新一个变化相对较少的画布。

Both of these problems tend to become acute as the number of elements on a Canvas increases.
这两个问题都会使得画布上的元素数量增加。

Important reminder: Whenever any drawable UI element on a given Canvas changes, the Canvas must re-run the batch building process. This process re-analyzes every drawable UI element on the Canvas, regardless of whether it has changed or not. Note that a “change” is any change which affects a UI object’s appearance, including the sprite assigned to a sprite renderer, transform position & scale, the text contained in a text mesh, etc.
重要提示:每当给定画布上的任何可绘制的UI元素发生变化时,画布必须重新运行批量构建过程。这个过程重新分析画布上的每一个可绘制的UI元素,不管它是否改变了。注意,“更改”是影响UI对象外观的任何更改,包括分配给精灵渲染器的精灵、转换位置和缩放、文本网格中包含的文本等。

Child order
子类顺序

Unity UIs are constructed back-to-front, with objects’ order in the hierarchy determining their sort order. Objects earlier in the hierarchy are considered behind objects later in the hierarchy. Batches are built by walking the hierarchy top-to-bottom and collecting all objects which use the same material, the same texture and do not have intermediate layers. An “intermediate layer” is a graphical object with a different material, whose bounding box overlaps two otherwise-batchable objects and is placed in the hierarchy between the two batchable objects. Intermediate layers force batches to be broken.
Unity UI是从前到后构建的,在层次结构中,对象的顺序决定了它们的排序顺序。层次结构中较早的对象将在层次结构中稍后的对象后面考虑。通过从上到下遍历层次结构并收集使用相同材质,相同纹理且没有中间层的所有对象来构建批次。“中间层”是一个具有不同材质的图形对象,它的边界框与两个可处理的对象重叠,并被放置在两个可批处理对象之间的层次结构中。中间层强制批次被破坏。

As discussed in the Unity UI Profiling Tools section, the UI profiler and frame debugger can be used to inspect a UI for intermediate layers. This is the situation where one drawable object interposes itself between two other drawable objects that are otherwise batchable.
正如在Unity UI Profiling Tools部分中所讨论的,UI profiler和frame debugger可以用来检查中间层的UI。在这种情况下,一个可绘制的对象在另外两个可拖放对象之间相互插入,而这些对象是可批的。

This problem most commonly occurs when text and sprites are located near one another: the text’s bounding box can invisibly overlap nearby sprites, because much of a text glyph’s polygon is transparent. This can be solved in two ways:
当文本和精灵彼此靠近时,这个问题最常见:文本的边界框可以明显地重叠在附近的精灵,因为文本字形的多边形大部分是透明的。这可以通过两种方式来解决:

      ●  Reorder the drawables so that the batchable objects are not interposed by the non-batchable object; that is, move the non-batchable object above or below the batchable objects.
          重新排序可绘制的对象,使可批处理的对象不被不可批处理的对象插入;也就是说,将不可批处理对象移动到可批处理的对象之上或之下。

      ●  Tweak the positions of the objects to eliminate invisible overlapping space.
          调整对象的位置以消除不可见的重叠空间。

Both of these operations can be carried out in the Unity Editor with the Unity Frame Debugger open and enabled. By simply observing the number of draw calls visible in the Unity Frame Debugger, it is possible to find an order and position that minimizes the number of draw calls wasted due to overlapping UI elements.
这两个操作都可以在Unity Editor中执行,Unity Frame Debugger打开并启用。通过简单地观察Unity Frame Debugger中可见的draw calls的数量,可以找到最小化由于UI元素重叠而浪费的draw calls的数量的顺序和位置。

Splitting Canvases
拆分画布

In all but the most trivial cases, it is generally a good idea to split up a Canvas, either by moving elements to a Sub-canvas or to a sibling Canvas.
除了最简单的情况外,通常来说,分割画布通常是一个好主意,可以将元素移动到子画布或兄弟的画布上。

Sibling Canvases are best used in cases where certain portions of a UI must have their draw depth controlled separately from the rest of the UI, to be always above or below other layers (e.g. tutorial arrows).
在UI的某些部分必须与UI的其余部分分开控制的情况下,在其他层(例如教程箭头)中,用户界面的绘制深度必须与UI的其他部分分开。

In most other cases, Sub-canvases are more convenient as they inherit their display settings from their parent Canvas.
在大多数其他情况下,子画布更方便,因为它们从父画布继承了它们的显示设置。

While it may seem at first glance that it is a best practice to subdivide a UI into many Sub-canvases, remember that the Canvas system also does not combine batches across separate Canvases. Performant UI design requires a balance between minimizing the cost of rebuilds and minimizing wasted draw calls.
虽然乍一看,将UI细分为许多子画布是一种最佳实践,但请记住,画布系统也不会在单独的画布之间进行批量处理。高性能UI设计需要在最小化重建成本和最大限度地减少浪费的draw calls之间取得平衡。

General guidelines
一般准则

Because a Canvas rebatches any time any of its constituent drawable components changes, it is generally best to split any non-trivial Canvas into at least two parts. Further, it is best to try to co-locate elements on the same Canvas if the elements are expected to change simultaneously. An example might be a progress bar and a countdown timer. These both rely on the same underlying data and therefore will require updates at the same time, and so they should be placed on the same Canvas.
由于画布在任何时候都可以重新批量修改,所以通常最好将任何非平凡的画布分成至少两部分。此外,如果元素预期同时发生变化,最好尝试在同一画布上共同定位元素。一个例子可能是一个进度条和一个倒计时计时器。它们都依赖于相同的底层数据,因此需要同时进行更新,因此它们应该放在相同的画布上。

On one Canvas, place all elements that are static and unchanging, such as backgrounds and labels. These will batch once, when the Canvas is first displayed, and then will no longer need to rebatch afterwards.
在一个画布上,放置所有静态和不变的元素,比如背景和标签。当画布首次显示时,这些将会批量处理,之后就不再需要重新批处理了。

On the second Canvas, place all of the “dynamic” elements – the ones that change frequently. This will ensure that this Canvas is rebatching primarily dirty elements. If the number of dynamic elements grows very large, it may be necessary to further subdivide the dynamic elements into a set of elements that are constantly changing (e.g. progress bars, timer readouts, anything animated) and a set of elements that change only occasionally.
在第二个画布上,放置所有的“动态”元素——那些经常变化的元素。这将确保这个画布主要重新调整被标记为dirty的元素。如果动态元素的数量变化非常大,可能需要进一步将动态元素细分为一组不断变化的元素(例如进度条、计时器读数、任何动画)和一组只偶尔更改的元素。

This is actually rather difficult in practice, especially when encapsulating UI controls into prefabs. Many UIs instead elect to subdivide a Canvas by splitting out the costlier controls onto a Sub-canvas.
在实践中,这实际上是相当困难的,特别是在将UI控件封装到prefabs中时。许多用户界面选择将昂贵的控件分割到子画布上,从而对画布进行细分。

Unity 5.2 and Optimized Batching
Unity 5.2和优化批处理

In Unity 5.2, the batching code was substantially rewritten, and is considerably more performant compared to Unity 4.6, 5.0 and 5.1. Further, on devices with more than 1 core, the Unity UI system will move most of the processing to worker threads. In general, Unity 5.2 reduces the need for aggressively splitting a UI into dozens of Sub-canvases. Many UIs on mobile devices can now be made performant with as few as two or three Canvases.
在Unity 5.2中,批处理代码基本上被重写,与Unity 4.6,5.0和5.1相比,性能更高。此外,在具有1个以上核心的设备上,Unity UI系统会将大部分处理移动到工作线程。一般来说,Unity 5.2减少了将UI拆分为几十个子画布的需求。移动设备上的许多ui都可以在两到三种画布上来实现。

More information on the optimizations in Unity 5.2 can be found in this blog post.
有关Unity 5.2中的优化的更多信息,请参阅此博客文章

Input and raycasting in Unity UI
Unity UI中输入和射线检测

By default, Unity UI uses the Graphic Raycaster component to handle input events, such as touch events and pointer-hover events. This is generally handled by the Standalone Input Manager component. Despite the name, the Standalone Input Manager is meant to be a “universal” input manager system, and will handle both pointers and touches.
默认情况下,Unity UI使用Graphic Raycaster组件来处理输入事件,例如触摸事件和指针悬停事件。这通常由独立输入管理器组件处理。尽管名称如此,独立输入管理器仍然是一个“通用”输入管理器系统,它将处理指针和触摸。

Erroneous mouse input detection on mobile (5.3)
移动设备上的错误鼠标输入检测(5.3)

Prior to Unity 5.4, each active Canvas with a Graphic Raycaster attached will run a raycast once per frame to check the position of the pointer so long as there is currently no touch input available. This will occur regardless of platform; iOS and Android devices without mice will still query the mouse’s position and attempt to discover which UI elements are beneath that position to determine if any hover events need to be sent.
在Unity 5.4之前,每个附加了Graphic Raycaster并激活的Canvas将每帧运行一次raycast,以检查指针的位置,只要当前没有可用的触摸输入。这将发生在任何平台;没有鼠标的iOS和Android设备仍然会查询鼠标的位置,并试图发现哪个UI元素在这个位置下面,以确定是否需要发送鼠标悬停事件。

This is a waste of CPU time, and has been witnessed consuming 5% or more of a Unity application’s CPU frame time.
这浪费了CPU时间,并且证实了占用Unity应用程序CPU帧时间的5%或更多。

This issue is resolved in Unity 5.4. From 5.4 onward, devices without mice will not query for the mouse position and will not perform unnecessary raycasts.
Unity 5.4中已解决此问题。从5.4开始,没有鼠标的设备将不会查询鼠标位置,也不会执行不必​​要的raycasts。

If using a version of Unity older than 5.4, it is strongly recommended that mobile developers create their own Input Manager class. This can be as simple as copying Unity’s Standard Input Manager from the Unity UI source and commenting out the ProcessMouseEvent method as well as all calls to that method.
如果使用早于Unity5.4的版本,强烈建议移动开发者创建他们自己的输入管理器类。这可以很简单,只需从Unity UI源复制Unity的标准输入管理器,并注释掉ProcessMouseEvent方法以及对该方法的所有调用。

Raycast optimization
射线检测优化

The Graphic Raycaster is a relatively straightforward implementation that iterates over all Graphic components that have the ‘Raycast Target’ setting set to true. For each Raycast Target, the Raycaster performs a set of tests. If a Raycast Target passes all of its tests, then it is added to the list of hits.
Graphic Raycaster是一个相对简单的实现,它遍历所有将“Raycast Target”设置为true的Graphic组件。对于每个Raycast目标,Raycaster执行一组测试。如果Raycast目标通过了所有测试,则会将其添加到命中列表中。

Raycast implementation details
射线检测实现细节

The tests are:
测试包括:

      ●  If the Raycast Target is active, enabled and is drawn (i.e. has geometry)
          如果Raycast目标是激活的,启用并绘制(即有几何图形)

      ●  If the input point lies within the RectTransform to which the Raycast Target is attached
          如果输入点位于连接Raycast目标的RectTransform中

      ●  If the Raycast Target has, or is a child (at any depth) of, any ICanvasRaycastFilter component, and that Raycast Filter component permits the Raycast.
          如果Raycast Target具有或者是任何ICanvasRaycastFilter组件的子级(在任何深度),并且该Raycast Filter组件允许Raycast。

The list of hit Raycast Targets is then sorted by depth, filtered for reversed targets, and filtered to ensure that elements rendered behind the camera (i.e. not visible in the screen) are removed.
然后,按照深度对命中的Raycast目标列表进行排序,对反向目标进行过滤,并进行过滤以确保删除在摄像机后面呈现的元素(即在屏幕中不可见)。

The Graphic Raycaster also may cast a ray into the 3D or 2D physics system if the respective flag is set on the Graphic Raycaster’s “Blocking Objects” property. (From script, the property is named blockingObjects.)
如果在Graphic Raycaster的“阻挡对象”属性上设置了相应的标志,则Graphic Raycaster也可以将光线投射到3D或2D物理系统中。(从脚本开始,该属性被命名为blockingObjects。)

If 2D or 3D blocking objects are enabled, then any Raycast Targets that draw beneath a 2D or 3D object on a raycast-blocking Physics Layer will also be eliminated from the list of hits.
如果启用了2D或3D阻挡对象,那么在光线投射阻挡物理层上的2D或3D对象下方绘制的任何Raycast目标也将从命中列表中删除。

The final list of hits is then returned.
然后返回最终的命中列表。

Raycasting optimization tips
射线检测优化技巧

Given that all Raycast Targets must be tested by the Graphic Raycaster, it is a best practice to only enable the ‘Raycast Target’ setting on UI components that must receive pointer events. The smaller the list of Raycast Targets, and the shallower the hierarchy that must be traversed, the faster each Raycast test will be.
鉴于必须由Graphic Raycaster测试所有Raycast目标,最佳做法是仅在必须接收指针事件的UI组件上启用“Raycast Target”设置。Raycast目标列表越小,必须遍历的层次越浅,每次Raycast测试的速度就越快。

For composite UI controls that have multiple drawable UI objects that must respond to pointer events, such as a button that wishes to have its background and text both change colors, it is generally better to place a single Raycast Target at the root of the composite UI control. When that single Raycast Target receives a pointer event, it can then forward the event to each interested component within the composite control.
对于具有多个可绘制UI对象的复合UI控件,它们必须对指针事件作出响应,比如希望拥有背景和文本的按钮都可以改变颜色,通常最好在复合UI控件的根部放置一个Raycast目标。当单个Raycast目标接收到一个指针事件时,它就可以将事件转发给组合控件中的每个感兴趣的组件。

Hierarchy depth and raycast filters
层次深度和射线检测过滤器。

Each Graphic Raycast traverses the Transform hierarchy all the way to the root when searching for raycast filters. The cost of this operation grows linearly in proportion to the depth of the hierarchy. All components found attached to each Transform in the hierarchy must be tested to see if they implement ICanvasRaycastFilter, so this is not a cheap operation.
当搜索Raycast过滤器时,每个Graphic Raycast都会遍历Transform层次结构。该操作的成本与层次结构的深度成线性增长。在层次结构中的每个Transform的所有组件都必须经过测试,以确定它们是否实现了ICanvasRaycastFilter,因此这不是一个简单的操作。

There are several standard Unity UI components that make use of ICanvasRaycastFilter, such as CanvasGroup, Image, Mask and RectMask2D, so this traversal cannot be eliminated trivially.
有几个标准的Unity UI组件使用ICanvasRaycastFilter,例如CanvasGroupImageMaskRectMask2D,因此这种遍历不能简单地删除。

Sub-canvases and the OverrideSorting property
子画布和OverrideSorting属性

The overrideSorting property on a Sub-canvas will cause a Graphic Raycast test to stop climbing the transform hierarchy. If it can be enabled without causing sorting or raycast detection issues, then it should be used to decrease the cost of raycast hierarchy traversals.
在子画布上的过度使用overrideSorting属性将导致一个图形Raycast测试停止攀登转换层次结构。如果可以在不引起排序或射线投射问题的情况下启用它,那么它应该被用来降低raycast层次结构的成本。


相关链接

  1. 原文地址: https://unity3d.com/cn/learn/tutorials/topics/best-practices/fill-rate-canvases-and-input